import 'dart:typed_data';

import 'package:inmotion_protocol/util/byte_util.dart';

/*
 * A fixed length int8 buffer array.
 *
 * Created by Jaren at 2021/8/17 16:21
 */
class Int8ListBuffer {
    Uint8ClampedList buffer = Uint8ClampedList(512);

    int readerIndex = 0;
    int writerIndex = 0;

    int readByte() {
        checkReadableBytes(1);
        int i = readerIndex;
        int byte = buffer[i];
        readerIndex = i + 1;
        return byte;
    }

    int readBytes(Uint8ClampedList out, [int dstIndex = 0, int length = 0]) {
        if (length == 0) length = out.length;
        checkReadableBytes(length);
        int readerIndexCopy = readerIndex;
        for (int i = 0; i < length; i++) {
            out[dstIndex + i] = buffer[readerIndexCopy + i];
        }
        return length;
    }

    Int8ListBuffer writeByte(int value) {
        ensureWritable(1);
        buffer[writerIndex++] = value;
        return this;
    }

    Int8ListBuffer writeBytes(Uint8ClampedList src, [int srcIndex = 0, int length = 0]) {
        if (length == 0) length = src.length;
        ensureWritable(src.length);
        ByteUtil.copy(src, srcIndex, buffer, writerIndex, length);
        writerIndex += length;
        return this;
    }

    Int8ListBuffer clear() {
        writerIndex = 0;
        readerIndex = 0;
        return this;
    }

    int get getReaderIndex => readerIndex;

    set setReaderIndex(int index) {
        readerIndex = index;
    }

    int get getWriterIndex => writerIndex;

    set setWriterIndex(int index) {
        writerIndex = index;
    }

    bool isReadable() {
        return readableBytes() > 0;
    }

    void checkReadableBytes(int minimumReadableBytes) {
        if (minimumReadableBytes < 0) {
            throw Exception("minimumReadableBytes: " + minimumReadableBytes.toString() + " (expected: >= 0)");
        }
        if (readerIndex > writerIndex - minimumReadableBytes) {
            throw Exception("readerIndex(" +
                readerIndex.toString() +
                ") + length(" +
                minimumReadableBytes.toString() +
                ") exceeds writerIndex(" +
                writerIndex.toString() +
                "): Int8ListBuffer");
        }
    }

    void ensureWritable(int minWritableBytes) {
        if (minWritableBytes < 0) {
            throw Exception("minWritableBytes: " + minWritableBytes.toString() + " (expected: >= 0)");
        }
        if (minWritableBytes <= writableBytes()) {
            return;
        }

        int writableBytesLength = writableBytes();

        if (minWritableBytes > writableBytesLength) {
            throw Exception("writerIndex(" +
                writerIndex.toString() +
                ") + minWritableBytes(" +
                minWritableBytes.toString() +
                ") exceeds writableBytes(" +
                writableBytesLength.toString() +
                "): Int8ListBuffer");
        }
    }

    int writableBytes() {
        return capacity() - writerIndex;
    }

    int readableBytes() {
        return writerIndex - readerIndex;
    }

    void resetReaderIndex() {
        readerIndex = 0;
    }

    void resetWriterIndex() {
        writerIndex = 0;
    }

    int capacity() {
        return buffer.length;
    }
}
